/// @NOTE: this file is included from Rect.hpp, IN cvMath:: namespace.

// ctors
template<typename T> Rect<T>::Rect() : l(0), r(1), t(1), b(0) {}
template<typename T> Rect<T>::Rect(T left, T right, T top, T bottom) : l(left), r(right), t(top), b(bottom) {}
template<typename T> template<typename J> Rect<T>::Rect(const Rect<J> &copy) : l(copy.l), r(copy.r), t(copy.t), b(copy.b) {}
/// Assing
template<typename T> Rect<T>& Rect<T>::operator=	(const Rect<T> &copy)
{ 	l = copy.l;
	r = copy.r;
	t = copy.t;
	b = copy.b;
	return *this;
}

template<typename T> Rect<T> operator+	(const Rect<T> &leftRect, const Rect<T> &rightRect)
{
	return Rect<T>(leftRect.l + rightRect.l, leftRect.r + rightRect.r, leftRect.t + rightRect.t, leftRect.b + rightRect.b);
}

template<typename T> Rect<T> operator-	(const Rect<T> &leftRect, const Rect<T> &rightRect)
{
	return Rect<T>(leftRect.l-rightRect.l, leftRect.r-rightRect.r, leftRect.t-rightRect.t, leftRect.b-rightRect.b);
}

template<typename T> Rect<T> operator*	(const Rect<T> &leftRect, const T realVal)
{
	return Rect<T>(leftRect.l*realVal, leftRect.r*realVal, leftRect.t*realVal, leftRect.b*realVal);
}

template<typename T> Rect<T> operator/	(const Rect<T> &leftRect, const T realVal)
{
	return Rect<T>(leftRect.l/realVal, leftRect.r/realVal, leftRect.t/realVal, leftRect.b/realVal);
}

// Assingment operators
template<typename T> Rect<T>& operator+=	(Rect<T> &leftRect, const Rect<T> &rightRect)
{
	leftRect.l += rightRect.l;
	leftRect.r += rightRect.r;
	leftRect.t += rightRect.t;
	leftRect.b += rightRect.b;
	return leftRect;
}

template<typename T> Rect<T>& operator-=	(Rect<T> &leftRect, const Rect<T> &rightRect)
{
	leftRect.l += rightRect.l;
	leftRect.r += rightRect.r;
	leftRect.t += rightRect.t;
	leftRect.b += rightRect.b;
	return leftRect;
}

template<typename T> Rect<T>& operator*=	(Rect<T> &leftRect, const T realVal)
{
	leftRect.l *= realVal;
	leftRect.r *= realVal;
	leftRect.t *= realVal;
	leftRect.b *= realVal;
	return leftRect;
}

template<typename T> Rect<T>& operator/=	(Rect<T> &leftRect, const T realVal)
{
	leftRect.l /= realVal;
	leftRect.r /= realVal;
	leftRect.t /= realVal;
	leftRect.b /= realVal;
	return leftRect;
}

template<typename T> void rectCorners(const Rect<T> & rect, Vec2<T> * vlt, Vec2<T> * vrt, Vec2<T> * vrb, Vec2<T> * vlb)
{
	if(vlt)	{ vlt->x = rect.l; vlt->y = rect.t; }
	if(vrt)	{ vrt->x = rect.r; vrt->y = rect.t; }
	if(vrb)	{ vrb->x = rect.r; vrb->y = rect.b; }
	if(vlb)	{ vlb->x = rect.l; vlb->y = rect.b; }
}

template<typename T> Rect<T> rotateRect(const Rect<T> &rect, const Vec2<T> & offset, T angle)
{
	cvMath::Vec2<T> p[3];
	Rect<T> rot(offset.x, offset.x, offset.y, offset.y);
	T _cos, _sin, xa, dx, dy;
	rectCorners<T>(rect, p, p+1, p+2, p+3);
	for(size_t i = 0; i < 4; ++i)
	{
		xa = atan2(p[i].y - offset.y, p[i].x - offset.x) + angle;
		_cos = cos(xa);
		_sin = sin(xa);
		dx = p[i].x - offset.x;
		dy = p[i].y - offset.y;
		dx = offset.x + ( _cos * dx + _sin * dy);
		dy = offset.y + (-_sin * dx + _cos * dy);
		rot.l = (dx < rot.l) ? dx : rot.l;
		rot.r = (dx > rot.r) ? dx : rot.r;
		rot.t = (dy > rot.t) ? dy : rot.t;
		rot.b = (dy < rot.b) ? dy : rot.b;
	}
	return rot;
}

template<typename T> Rect<T> offsetRect(const Rect<T> & rect, const Vec2<T> & offset)
{
	Rect<T> result;
	result.l = rect.l + offset.x;
	result.r = rect.r + offset.x;
	result.t = rect.t + offset.y;
	result.b = rect.b + offset.y;
	return result;
}

template<typename T> Rect<T> expandRect(const Rect<T> &rectA, const Vec2<T> &point)
{
	return Rect<T>(std::min(rectA.l, point.x),
					std::max(rectA.r, point.x),
					std::max(rectA.t, point.y),
					std::min(rectA.b, point.y));
}

template<typename T> Rect<T> unionRects(const Rect<T> & rectA, const Rect<T> & rectB)
{
	return Rect<T>(std::min(rectA.l, rectB.l),
					std::max(rectA.r, rectB.r),
					std::max(rectA.t, rectB.t),
					std::min(rectA.b, rectB.b));
}

template<typename T> Rect<T> intersectRects(const Rect<T> & rectA, const Rect<T> & rectB)
{
	return Rect<T>(std::max(rectA.l, rectB.l),
					std::min(rectA.r, rectB.r),
					std::min(rectA.t, rectB.t),
					std::max(rectA.b, rectB.b));
}

template<typename T> T rectWidth(const Rect<T> & rect)	{ return rect.r - rect.l; }
template<typename T> T rectHeight(const Rect<T> & rect)	{ return rect.b - rect.t; }

template<typename T> bool rectContains(const Rect<T> & rect, const Vec2<T> & p)
{
	return (p.x >= rect.l && p.x <= rect.r) && (p.y <= rect.t && p.y >= rect.b);
}


template<typename T> bool rectContains(const Rect<T> & outer, const Rect<T> & inner)
{
	Vec2<T> p[4];
	rectCorners<T>(inner, p, p+1, p+2, p+3);
	for(size_t i = 0; i < 4; ++i)
	{
		if(!rectContains<T>(outer, p[i]))	{ return false; }
	}
	return true;
}

template<typename T> bool rectIntersect(const Rect<T> & rectA, const Rect<T> & rectB)
{
	Vec2<T> p[4];
	rectCorners<T>(rectB, p, p+1, p+2, p+3);
	for(size_t i = 0; i < 4; ++i)
	{
		if(rectContains<T>(rectA, p[i]))	{ return true; }
	}

	rectCorners<T>(rectA, p, p+1, p+2, p+3);
	for(size_t i = 0; i < 4; ++i)
	{
		if(rectContains<T>(rectB, p[i]))	{ return true; }
	}

	return false;
}
